/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package SnpDbHandling;

import SnpDbEntities.User;
import SnpDbEntities.UserPermissions;
import java.rmi.RemoteException;
import SnpDbHndInterfaces.DBUsrHandling;
import java.sql.*;
import java.util.LinkedHashMap;
import java.util.logging.Level;

/**
 * Class which implements DBUsrHandling interface and realizes it's functionality.
 * @author Łukasz 'byku' Guzik
 */
public class DBUsrHandler extends java.rmi.server.UnicastRemoteObject
	implements
	DBUsrHandling
{
    final private Connection dbCon;
    final public User connectedUser;

    DBUsrHandler(Connection con, User usr) throws RemoteException
    {
	dbCon = con;
	connectedUser = usr;
    }

    @Override
    public User getUser(int iID) throws RemoteException
    {
	User tmp = new User();
	tmp.setId(iID);
	return getUser(tmp, false);
    }

    @Override
    public User getUser(String strLogin) throws RemoteException
    {
	User tmp = new User();
	tmp.setLogin(strLogin);
	return getUser(tmp, true);
    }

    @Override
    public LinkedHashMap<Integer, User> getUsersList() throws RemoteException
    {
	UserRecord userRecord = null;
	LinkedHashMap<Integer, User> usersList = new LinkedHashMap<Integer, User>();
	try
	{
	    Statement stmt = dbCon.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
	    String query = "SELECT * FROM Users;";

	    ResultSet rs = stmt.executeQuery(query);
	    while(rs.next())
	    {
		userRecord = UserRecord.getFromResultSet(rs);
		userRecord.getUser().annonimizeSensibleData(connectedUser);
		usersList.put(userRecord.getUser().getId(), userRecord.getUser());
	    }
	    stmt.close();
	} catch(SQLException e)
	{
	    DBHndLogger.logException(Level.WARNING, e);
	    return null;
	}
	return usersList;
    }

    private User getUser(User usr, boolean byLogin)
    {
	UserRecord resultRecord = null;
	User resultUser = null;
	try
	{
	    PreparedStatement stmt;

	    if(byLogin)
	    {
		stmt = dbCon.prepareStatement("SELECT * FROM USERS WHERE Login = ?;");
		stmt.setString(1, usr.getLogin());
	    } else
	    {
		stmt = dbCon.prepareStatement("SELECT * FROM USERS WHERE ID = ?;");
		stmt.setInt(1, usr.getId());
	    }

	    ResultSet rs = stmt.executeQuery();
	    if(rs.next())
	    {
		resultRecord = UserRecord.getFromResultSet(rs);
	    }
	    stmt.close();
	} catch(SQLException e)
	{
	    DBHndLogger.logException(Level.WARNING, e);
	    return null;
	}

	if(resultRecord != null)
	{
	    resultUser = resultRecord.getUser();
	    resultUser.annonimizeSensibleData(connectedUser);
	}
	return resultUser;
    }

    @Override
    public int addUser(User newUser) throws RemoteException
    {
	int result = -1;
	UserRecord newUserRecord = new UserRecord(newUser);
	if(!connectedUser.canAddUser(newUser))
	    return -1;

	try
	{
	    Statement stmt = dbCon.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
	    String query = "SELECT * FROM Users WHERE ID = -1";
	    ResultSet rs = stmt.executeQuery(query);
	    rs.moveToInsertRow();
	    newUserRecord.addToResultSet(rs);
	    rs.insertRow();
	    rs.first();
	    result = rs.getInt("ID");
	    stmt.close();
	} catch(SQLException e)
	{
	    DBHndLogger.logException(Level.WARNING, e);
	    return -1;
	}
	return result;
    }

    @Override
    public boolean updateUser(User newUserData) throws RemoteException
    {
	User userToUpdate;
	try
	{
	    Statement stmt = dbCon.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
	    String query = "SELECT * FROM Users WHERE ID = " + newUserData.getId() + ";";
	    ResultSet rs = stmt.executeQuery(query);
	    if(rs.next())
	    {
		UserRecord userToUpdateRecord;
		userToUpdateRecord = UserRecord.getFromResultSet(rs);
		userToUpdate = userToUpdateRecord.getUser();

		if(!connectedUser.canUpdateUser(userToUpdate, newUserData))
		{
		    stmt.close();
		    return false;
		}

		if((connectedUser.getPermissions() == UserPermissions.MODERATOR
			|| connectedUser.getPermissions() == UserPermissions.NORMAL_USER)
			&& connectedUser.getId() != userToUpdate.getId())
		{
		    newUserData.setPwdHash("0");
		}

		UserRecord newUserValuesRecord = new UserRecord(newUserData);
		newUserValuesRecord.updateInResultSet(rs);
		rs.updateRow();
	    } else
	    {
		stmt.close();
		return false;
	    }
	    stmt.close();
	} catch(SQLException e)
	{
	    DBHndLogger.logException(Level.WARNING, e);
	    return false;
	}
	return true;
    }

    @Override
    public boolean deleteUser(int deleteID) throws RemoteException
    {
	try
	{
	    Statement stmt = dbCon.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
	    String query = "SELECT * FROM Users WHERE ID = " + deleteID + ";";
	    ResultSet rs = stmt.executeQuery(query);
	    UserRecord userToDelete;

	    if(rs.next())
	    {
		userToDelete = UserRecord.getFromResultSet(rs);
		if(!connectedUser.canDeleteUser(userToDelete.getUser()))
		{
		    stmt.close();
		    return false;
		}
		rs.deleteRow();
	    } else
	    {
		stmt.close();
		return false;
	    }
	    stmt.close();
	} catch(SQLException e)
	{
	    DBHndLogger.logException(Level.WARNING, e);
	    return false;
	}
	return true;
    }

    @Override
    public boolean enableUser(int iID) throws RemoteException
    {
	return disEnableUser(iID, true);
    }

    @Override
    public boolean disableUser(int iID) throws RemoteException
    {
	return disEnableUser(iID, false);
    }

    private boolean disEnableUser(int userID, boolean enable) throws
	    RemoteException
    {
	User userToChange = getUser(userID);
	if(userToChange == null || !connectedUser.canDisEnableUser(userToChange))
	    return false;
	userToChange.setEnabled(enable);
	return updateUser(userToChange);
    }
}
